#
# This package handles all access to matrices, storing, modifying, etc.
# Keeps knowledge of data format encapsulated from other modules for cleaner interface
# Matrix indices start at 1,1 to stay consistent with math standards
#
# 2009 Mike Widner <mikewidner@gmail.com>
#
###########

package Fangcheng::Matrix;

use 5.006001;
use strict;
use warnings;
use Carp;
use vars qw(@ISA);

require Fangcheng;

@ISA = qw( Fangcheng );

my $VERSION = '0.01';

##### Methods #####

# instantiate new blessed object
# each instance of this class handles a single matrix to make calculations clearer
# can have number of rows and columns defined; initializes them to given value or random
# if we let Perl autovivify, fields will be undefined, which causes things to croak
sub new {
	my ($class, $rowMax, $init, $randMax) = @_;
	my $self;
	# default to zeroed out matrix
	if (not defined $init) {
		$init = 0;
	}
		
	if (defined $rowMax) {
		my $columnMax = $rowMax + 1;	# augmented matrices have 1 more column than rows
		foreach my $row ( 1 .. $rowMax ) {
			foreach my $col ( 1 .. $columnMax ) {
				# random array?
				if ($init eq 'rand') {
					if (not defined $randMax) {
						croak "Need upper limit for random initialization";
					}
					$self->[$row][$col] = int(rand($randMax)); 
				}
				else {
					$self->[$row][$col] = $init;
				}
			}
		}
	}
	else {
		# empty nested array, outer array is rows, inner is columns
		$self = [[]];
	}
		
	return(bless $self, ref($class) || $class);
}

# sets value of single field identified by row and column
sub set {
	my ($self, $row, $col, $val) = @_ or croak("Needs row, column, and value to set");
	if ($row == 0 or $col == 0) {
		croak "Matrix index starts at 1,1";
	}
	if ( $row > $self->rows() or $col > $self->columns() ) {
		croak "Input for $row, $col out of bounds";
	}
	$self->[$row][$col] = $val;
}

# returns the value of a single field identified by row and column
sub get {
	my ($self, $row, $col) = @_ or croak("Needs row, and column");
	if (defined $self->[$row][$col]) {
		return( $self->[$row][$col] );
	}
	croak("No value defined for $row, $col");
}

# returns the number of rows in a matrix
sub rows {
	my ($self) = shift;
	return( scalar(@{ $self }) - 1); # subtract 1 because we start at 1,1
}

# returns the number of columns in a matrix
sub columns {
	my ($self) = shift;
	return( scalar(@{ $self->[1] }) - 1);
}

# copies one matrix to another, returns new matrix object
sub copy {
	my ($self) = shift;
	
	# create a new object, then copy all data into it
	my $matrixCopy = ref($self)->new( $self->rows() );
	foreach my $row ( 1 .. $self->rows() ) {
		foreach my $col ( 1 .. $self->columns() ) {
			$matrixCopy->set( $row, $col, $self->get( $row, $col ) );
		}
	}
	return($matrixCopy);
}

1;
__END__


=head1 NAME

FangchengMatrix - Perl extension for calculating Chinese linear algebra

=head1 SYNOPSIS

  use FangchengMatrix;

=head1 DESCRIPTION

This class encapsulates all access to matrices by creating a single object per matrix.

=head2 EXPORT

None by default.

